package day31.homework;

import java.io.*;
import java.net.*;
import java.util.*;

/**
 * TCP服务器程序
 * 实现接收客户端发送的老师信息并写入本地文件的功能
 * 
 * TCP（传输控制协议）是一种面向连接的、可靠的、基于字节流的传输层通信协议
 * 服务器工作流程：
 * 1. 创建ServerSocket并绑定到指定端口
 * 2. 等待客户端连接请求
 * 3. 接受客户端连接，创建Socket对象
 * 4. 通过Socket的输入输出流与客户端进行数据交互
 * 5. 处理完数据后关闭连接
 */
public class Server {
    /**
     * 程序入口点
     * main方法是Java程序的执行起点
     * @param args 命令行参数数组
     * @throws Exception 抛出所有可能的异常
     */
    public static void main(String[] args) throws Exception {
        // 在控制台输出提示信息，表示服务器正在启动
        System.out.println("服务器启动中");
        
        // 创建服务器套接字并绑定到指定端口
        // ServerSocket是服务器端的套接字，用于监听客户端连接请求
        // 端口号8002是自定义的端口号，范围是0-65535，其中0-1023是系统保留端口
        ServerSocket serverSocket = new ServerSocket(8002);
        // 输出服务器启动成功的提示信息
        System.out.println("服务器已启动，监听端口: 8002");
        
        // 循环等待客户端连接
        // 这是一个无限循环，服务器将持续运行并等待客户端连接
        // true是布尔值，表示条件永远为真
        while (true) {
            // 等待客户端连接
            // accept()方法会阻塞当前线程，直到有客户端连接请求到达
            // 当有客户端连接时，该方法会返回一个Socket对象，用于与客户端通信
            Socket clientSocket = serverSocket.accept();
            // 输出客户端连接成功的提示信息
            System.out.println("客户端已连接");
            
            // 处理客户端请求
            // 调用handleClient方法处理与客户端的通信
            // 这样可以将连接处理逻辑分离，使代码更清晰
            handleClient(clientSocket);
        }
    }
    
    /**
     * 处理客户端连接
     * 这个方法负责与客户端进行具体的通信操作
     * @param clientSocket 客户端套接字，用于与特定客户端通信
     * @throws Exception 抛出所有可能的异常
     */
    private static void handleClient(Socket clientSocket) throws Exception {
        // 创建输入流，用于接收客户端的数据
        // ObjectInputStream用于读取对象流，可以读取Java对象
        // getInputStream()方法返回Socket的输入流，用于从客户端接收数据
        ObjectInputStream in = new ObjectInputStream(clientSocket.getInputStream());
        
        // 创建输出流，用于向客户端发送数据
        // ObjectOutputStream用于写入对象流，可以发送Java对象
        // getOutputStream()方法返回Socket的输出流，用于向客户端发送数据
        ObjectOutputStream out = new ObjectOutputStream(clientSocket.getOutputStream());
        
        // 创建文件写入流，用于将老师信息写入文件
        // FileWriter用于写入字符文件
        // PrintWriter提供了更方便的打印方法，如println()
        // "teacher.txt"是文件名，false表示不追加而是覆盖写入
        PrintWriter fileWriter = new PrintWriter(new FileWriter("teacher.txt", false));
        
        // 接收客户端发送的老师列表
        // readObject()方法从输入流中读取一个对象
        // 由于网络传输的是字节流，需要强制类型转换为ArrayList
        // 这里使用了泛型的原始类型，应该使用ArrayList<Teacher>
        ArrayList teachers = (ArrayList) in.readObject();
        
        // 输出接收到的老师信息数量
        System.out.println("接收到" + teachers.size() + "条老师信息:");
        
        // 遍历输出老师信息并写入文件
        // 使用for循环遍历ArrayList中的每个元素
        for (int i = 0; i < teachers.size(); i++) {
            // 从ArrayList中获取老师对象并强制类型转换为Teacher类型
            Teacher teacher = (Teacher) teachers.get(i);
            // 在控制台输出老师信息
            System.out.println(teacher);
            // 将老师信息写入文件，格式为"姓名-年龄-工资"
            // getName()、getAge()、getSalary()是Teacher类的getter方法
            fileWriter.println(teacher.getName() + "-" + teacher.getAge() + "-" + teacher.getSalary());
        }
        
        // 确保数据写入文件
        // flush()方法强制将缓冲区的数据写入到文件中
        fileWriter.flush();
        
        // 输出文件写入成功的提示信息
        System.out.println("老师信息已写入teacher.txt文件");
        
        // 向客户端发送确认信息
        // writeObject()方法将对象写入输出流
        // "ok"是确认信息，告诉客户端服务器已成功处理请求
        out.writeObject("ok");
        // 强制将缓冲区的数据发送出去
        out.flush();
        
        // 关闭所有资源
        // 按照先开后关的原则，最后打开的流最先关闭
        fileWriter.close();  // 关闭文件写入流
        out.close();         // 关闭对象输出流
        in.close();          // 关闭对象输入流
        clientSocket.close(); // 关闭客户端套接字连接
        
        // 输出客户端断开连接的提示信息
        System.out.println("客户端断开连接");
    }
}